package com.example.service;

import com.example.model.Person;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
public class ElasticsearchService {

    private final RestHighLevelClient client;
    private final ObjectMapper objectMapper;
    private static final String INDEX_NAME = "my_index";
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @PostConstruct
    public void init() {
        try {
            // 检查索引是否存在
            boolean indexExists = client.indices().exists(new GetIndexRequest(INDEX_NAME), RequestOptions.DEFAULT);

            // 如果索引不存在，创建索引
            if (!indexExists) {
                log.info("Creating index: {}", INDEX_NAME);
                
                // 读取索引映射文件
                Resource mappingResource = new ClassPathResource("my_index.json");
                String mappingJson;
                
                try (InputStream is = mappingResource.getInputStream()) {
                    mappingJson = new String(is.readAllBytes());
                }
                
                // 创建索引请求
                CreateIndexRequest createIndexRequest = new CreateIndexRequest(INDEX_NAME);
                
                // 配置索引设置
                createIndexRequest.settings(Settings.builder()
                        .put("index.number_of_shards", 3)
                        .put("index.number_of_replicas", 2)
                        .build());
                
                // 设置映射
                createIndexRequest.mapping(mappingJson, XContentType.JSON);
                
                // 创建索引
                CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
                log.info("Index created: {}, acknowledged: {}", 
                        createIndexResponse.index(), createIndexResponse.isAcknowledged());
                
                // 创建索引后加载测试数据
                loadTestData();
            } else {
                // 检查索引中是否已有数据
                SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
                searchSourceBuilder.query(QueryBuilders.matchAllQuery());
                searchSourceBuilder.size(0); // 只需要计数，不需要返回数据
                searchRequest.source(searchSourceBuilder);
                
                SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
                long count = searchResponse.getHits().getTotalHits().value;
                
                if (count == 0) {
                    log.info("Index exists but has no data. Loading test data...");
                    loadTestData();
                } else {
                    log.info("Index already exists and contains {} documents.", count);
                }
            }
        } catch (Exception e) {
            log.error("Error initializing Elasticsearch", e);
        }
    }

    public void loadTestData() {
        try {
            Resource dataResource = new ClassPathResource("test_data.json");
            
            // 配置对象映射器以支持Java 8日期时间
            objectMapper.registerModule(new JavaTimeModule());
            
            List<TestDataItem> items;
            
            try (InputStream is = dataResource.getInputStream()) {
                // 读取JSON文件中的测试数据
                items = objectMapper.readValue(is, new TypeReference<List<TestDataItem>>() {});
            }
            
            if (items.isEmpty()) {
                log.warn("No test data found");
                return;
            }
            
            // 批量插入数据
            BulkRequest bulkRequest = new BulkRequest();
            
            for (TestDataItem item : items) {
                // 将TestDataItem转换为Person对象
                Person person = new Person(
                        item.getName(),
                        item.getAge(),
                        LocalDate.parse(item.getCreatedAt(), DATE_FORMATTER)
                );
                
                // 创建索引请求并添加到批量请求中
                IndexRequest indexRequest = new IndexRequest(INDEX_NAME)
                        .source(objectMapper.writeValueAsString(person), XContentType.JSON);
                
                bulkRequest.add(indexRequest);
            }
            
            // 执行批量请求
            BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            
            if (bulkResponse.hasFailures()) {
                log.error("Bulk had errors: {}", bulkResponse.buildFailureMessage());
            } else {
                log.info("Successfully loaded {} test documents in {} ms", 
                        items.size(), bulkResponse.getTook().getMillis());
            }
            
        } catch (IOException e) {
            log.error("Error loading test data", e);
        }
    }
    
    // 内部类用于解析JSON数据
    private static class TestDataItem {
        private String name;
        private int age;
        private String createdAt;
        
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
        
        public int getAge() {
            return age;
        }
        
        public void setAge(int age) {
            this.age = age;
        }
        
        public String getCreatedAt() {
            return createdAt;
        }
        
        public void setCreatedAt(String createdAt) {
            this.createdAt = createdAt;
        }
    }
} 